<?php

  /**
   * @author Dany Mottier
   * @version 2.3.3
   */
  class Socket extends Base implements ISocket {

    /** @var IString The ip, host name or url to connect to. */
    private $hostname = "";

    /** @var IInteger The port to connect to. */
    private $port = 80;

    /** @var int The error number when encountered. */
    private $error_number = 0;

    /** @var string The error string when encountered. */
    private $error_string = "";

    /** @var IInteger The timeout for stopping script. */
    private $timeout = 5;

    /** @var resource The socket pointer. */
    private $pointer = NULL;

    /**
     * Store all parameters in private variables.
     *
     * @param string $hostname The hostname to connect to.
     * @param integer $port The port to connect to.
     * @param integer $timeout The timeout for stopping script.
     */
    public function __construct($hostname = "127.0.0.1", $port = 80, $timeout = 30) {
      $this->hostname = new String($hostname);
      $this->port = new Integer($port);
      $this->timeout = new Integer($timeout);
    }

    /**
     * Returns the specified hostname.
     * @return IString The specified hostname.
     */
    public function getHostname() {
      return $this->hostname;
    }

    /**
     * Returns the specified port.
     * @return IInteger The specified port.
     */
    public function getPort() {
      return $this->port;
    }

    /**
     * Returns he error number when encountered.
     * @return IInteger The error number.
     */
    public function getErrorNumber() {
      return new Integer($this->error_number);
    }

    /**
     * Returns the error string when encountered.
     * @return IString The error.
     */
    public function getErrorString() {
      return new String($this->error_string);
    }

    /**
     * Returns the specified timeout.
     * @return IInteger The timeout.
     */
    public function getTimeout() {
      return $this->timeout;
    }

    /**
     * Sets the hostname to connect to.
     * @param string $value The target.
     */
    public function setHostname($value) {
      $this->hostname = new String($value);
    }

    /**
     * Sets the port to connect to.
     * @param integer $value The port.
     */
    public function setPort($value) {
      $this->port = new Integer($value);
    }

    /**
     * Sets the timeout.
     * @param integer $value The timeout.
     */
    public function setTimeout($value) {
      $this->timeout = new Integer($value);
    }

    /**
     * Open Internet or Unix domain socket connection.<br />
     * Initiates a socket connection to the resource specified by hostname .
     * PHP supports hostnames in the Internet and Unix domains as described in
     * List of Supported Socket Transports. A list of supported transports can
     * also be retrieved using stream_get_transports().
     * The socket will by default be opened in blocking mode. You can switch it
     * to non-blocking mode by using stream_set_blocking().
     *
     * @param const $protocol Defines the protocol to use to connect to host.
     *
     * @link http://be.php.net/manual/en/transports.php
     * @link http://be.php.net/manual/en/function.fsockopen.php
     */
    public function connect($protocol = "") {
      $this->pointer = fsockopen($protocol . $this->hostname->toString(), $this->port->integerValue(), $this->error_number, $this->error_string, $this->timeout->integerValue());

      return!is_null($this->pointer);
    }

    /**
     * Check if the resource pointer is linked to a stream or not.
     * @return IBoolean True if the socket is connected, false otherwise.
     * @link http://be2.php.net/manual/en/function.empty.php
     */
    public function isConnected() {
      return new Boolean(!empty($this->pointer));
    }

    /**
     * Closes the open socket pointer.
     * @return IBoolean True on success or false on failure.
     * @link http://be.php.net/manual/en/function.fclose.php
     */
    public function disconnect() {
      $return = false;
      if (!is_null($this->pointer)) {
        $return = fclose($this->pointer);
      }
      return new Boolean($return);
    }

    /**
     * Tests for end-of-stream on a socket pointer.
     * @return IBoolean True if the file pointer is at EOF or an error occurs (including socket timeout); otherwise returns false.
     * @link http://be.php.net/manual/en/function.feof.php
     */
    public function endOfStream() {
      return new Boolean(feof($this->pointer));
    }

    /**
     * Retrieve list of registered socket transports.
     * @return array An indexed array containing the name of all socket transports available on the running system.
     * @link http://be.php.net/manual/en/function.stream-get-transports.php
     */
    public static function getTransport() {
      return stream_get_transports();
    }

    /**
     * Gets line from socket pointer.
     * @param integer $length The length to read, by default, setted to 1024.
     * @return IString The read content from the socket.
     * @link http://be.php.net/manual/en/function.fgets.php
     */
    public function read(IInteger $length) {
      return new String(fgets($this->pointer, $length->integerValue()));
    }

    /**
     * Set socket to blocking or non-blocking mode.
     * @param const $mode The mode to apply on the socket.
     * @return IBoolean True on success or false on failure.
     * @link http://be.php.net/manual/en/function.stream-set-blocking.php
     */
    public function setBlocking($mode = ISocket::BLOCKING) {
      if ($mode == self::BLOCKING || $mode == self::NON_BLOCKING) {
        return new Boolean(stream_set_blocking($this->pointer, $mode));
      }
    }

    /**
     * Binary-safe socket write.<br />
     * Writes the contents of string to the socket stream pointed to by handle.
     * @param IString $stream The stream to write in the socket.
     * @return IInteger The number of bytes written, or false on error.
     * @link http://be.php.net/manual/en/function.fwrite.php
     */
    public function write(IString $stream) {
      return new Integer(fwrite($this->pointer, $stream->toString()));
    }

    /**
     * Binary-safe socket write.<br />
     * Writes the contents of string to the socket stream pointed to by handle ended by '\r\n'.
     * @param IString $stream The stream to write in the socket.
     * @return IInteger The number of bytes written, or false on error.
     */
    public function writeLine(IString $stream) {
      return new Integer(fwrite($this->pointer, $stream->toString() . self::EOL));
    }

  }

?>
